using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using UDS.Management.Data;
using UDS.Management.Data.Package;


namespace UDS.Build.Database
{
    [LoadInSeparateAppDomain]
    public class DatabaseCreate : MarshalByRefObject, ITask
    {
        private string SqlInstance;
        private string DBName;
        private string DBManifest;
        private bool DropDB = false;
        protected TaskLoggingHelper Log;

        public DatabaseCreate()
        {
            Log = new TaskLoggingHelper(this);
        }

        [Required]
        public string DatabaseName
        {
            get
            {
                return DBName;
            }
            set
            {
                DBName = value;
            }
        }

        [Required]
        public string SqlServerInstance
        {
            get
            {
                return SqlInstance;
            }
            set
            {
                SqlInstance = value;
            }
        }

        [Required]
        public string Manifest
        {
            get
            {
                return DBManifest;
            }
            set
            {
                DBManifest = value;
            }
        }

        public string BuildAction
        {
            get;
            set;
        }

        public bool DropDatabase
        {
            get
            {
                return DropDB;
            }
            set
            {
                DropDB = value;
            }
        }

        private void TestDatabase_OnUpdate(object sender, UDS.Management.Data.Database.DatabaseUpdateEvent update)
        {
            if (!String.IsNullOrEmpty(update.Name))
            {
                this.Log.LogMessage(MessageImportance.High, update.Name);
            }
        }

        #region ITask Members

        private IBuildEngine buildEngine;

        public IBuildEngine BuildEngine
        {
            get
            {
                return buildEngine;
            }
            set
            {
                buildEngine = value;
            }
        }

        private ITaskHost hostObject;

        public ITaskHost HostObject
        {
            get
            {
                return hostObject;
            }
            set
            {
                hostObject = value;
            }
        }

        private UDS.Management.Data.Database.DatabaseUpdateContext GetBuildAction()
        {
            if (string.IsNullOrEmpty(BuildAction))
            {
                return UDS.Management.Data.Database.DatabaseUpdateContext.Configure
                | UDS.Management.Data.Database.DatabaseUpdateContext.Functions
                | UDS.Management.Data.Database.DatabaseUpdateContext.PostInstall
                | UDS.Management.Data.Database.DatabaseUpdateContext.PreInstall
                | UDS.Management.Data.Database.DatabaseUpdateContext.Publish
                | UDS.Management.Data.Database.DatabaseUpdateContext.Replication
                | UDS.Management.Data.Database.DatabaseUpdateContext.Schema
                | UDS.Management.Data.Database.DatabaseUpdateContext.StoredProcedures
                | UDS.Management.Data.Database.DatabaseUpdateContext.Unpublish
                | UDS.Management.Data.Database.DatabaseUpdateContext.Views
                | UDS.Management.Data.Database.DatabaseUpdateContext.GenerateSQLJobs;
            }
            UDS.Management.Data.Database.DatabaseUpdateContext rc = 0;
            string[] actions = BuildAction.Split(new char[] { ' ', ';', ',' });
            foreach (string action in actions)
            {
                rc |= (UDS.Management.Data.Database.DatabaseUpdateContext)Enum.Parse(typeof(UDS.Management.Data.Database.DatabaseUpdateContext), action);
            }
            return rc;
        }

        public bool Execute()
        {
            if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("__DEBUG_BUILD_TASK")))
            {
                while (!System.Diagnostics.Debugger.IsAttached)
                {
                    Log.LogMessage(MessageImportance.Low, "Waiting for debugger to attach");
                    System.Threading.Thread.Sleep(500);
                }
            }

            //System.Diagnostics.Debugger.Break();
            PackageLoader packageLoader = new PackageLoader();
            try
            {
                IDBPackage PackageInterface = null;
                System.Reflection.Assembly DBAssembly = System.Reflection.Assembly.LoadFile(DBManifest);
                packageLoader.LoadPackages(DBAssembly);
                foreach (string packageName in packageLoader.GetPackageNames())
                {
                    // The assembly is assumed to contain only 1 DB package
                    PackageInterface = packageLoader.GetPackage(packageName);
                    break;
                }

                UDS.Management.Data.Database CreateTestDatabase = new UDS.Management.Data.Database(SqlInstance, DBName);
                CreateTestDatabase.OnUpdate += new UDS.Management.Data.Database.DatabaseUpdateDelegate(TestDatabase_OnUpdate);

                if (DropDB)
                {
                    if (CreateTestDatabase.Exists())
                    {
                        Log.LogMessage(MessageImportance.High, "Dropping database {0} on server {1}", DBName, SqlInstance);
                        CreateTestDatabase.DropDatabase(DBName);
                    }

                    // Create the database
                    Log.LogMessage(MessageImportance.High, "Creating database {0} on server {1}", DBName, SqlInstance);
                    CreateTestDatabase.CreateDatabase(DBName);
                }

                Log.LogMessage(MessageImportance.High, "Applying database package {0} to database {1} on server {2}", PackageInterface.GetPackageName(), DBName, SqlInstance);
                // Now connect to it
                UDS.Management.Data.Database TestDatabase = new UDS.Management.Data.Database(SqlInstance, DBName);

                TestDatabase.OnUpdate += new UDS.Management.Data.Database.DatabaseUpdateDelegate(TestDatabase_OnUpdate);
                // Update it with the schema, but don't update the jobs
                TestDatabase.UpdateDatabase(PackageInterface, GetBuildAction(), true);

                return true;
            }
            catch (UDS.Management.Data.Exceptions.SqlScriptException scriptEx)
            {
                string msg;
                if (scriptEx.InnerException != null)
                {
                    msg = scriptEx.InnerException.Message;
                }
                else
                {
                    msg = scriptEx.Message;
                }
                this.Log.LogError(null, "SQL", null, scriptEx.ScriptName, (int)scriptEx.StartLineNumber, 1, (int)scriptEx.EndLineNumber, 1, msg);
                return false;
            }
            catch (System.Data.SqlClient.SqlException sqlEx)
            {
                this.Log.LogErrorFromException(sqlEx);
                this.Log.LogError("If a database server is not installed on this machine, use the BuildUnittestDatabase environment variable to disable database creation.  "
                    + "Use the UnittestSqlServerInstance environment variable to set test database server name.");
                return false;
            }
            catch (Exception e)
            {
                this.Log.LogErrorFromException(e);
                return false;
            }
        }



        #endregion
    }
}
